home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / cheat / infocom6.zip / VOCAB.C next >
Text File  |  1991-08-21  |  16KB  |  531 lines

  1. #define INFO "\
  2. vocab -- A data dumper\n\
  3. Copyleft (c) 1991 by Mike Threepoint.  All rights reversed.\n\
  4. Release 6 / Serial number 910608\n\
  5. \n\
  6. Display a vocabulary list of an Infocom(tm) adventure game data file.\n\
  7. \n\
  8. Usage:  vocab [-1] [-w] [-#] [-f] file...\n\
  9. \n\
  10. \t-1   one-column list\n\
  11. \t-w   wide list (default)\n\
  12. \t-#   toggle word numbers\n\
  13. \t-f   toggle flags\n\
  14. \n"
  15.  
  16. /* Now you can:
  17.  *    make sure you've seen every last Encyclopedia Frobizzica entry,
  18.  *    learned every spell in the Enchanter series,
  19.  *    know all the magic wand's F-words,
  20.  *    discover obscure synonyms (like calling the Zorkian elvish sword
  21.  *       Glamdring, the dragon Smaug, and the robot R2D2)
  22.  *    learn trivia about the game's internal operations (like the internal
  23.  *       `intnum' noun in several games, used when you type a number)
  24.  *    play with curious debugging commands hidden in some games (Stu Galley's
  25.  *       works are good for this)
  26.  *
  27.  * I doubt Infocom's employees will complain, either of them.  Alas, Infocom.
  28.  * I wore a black armband when you went under.  If only you'd stayed solvent.
  29.  * (At least till I could buy Sherlock and Arthur!  Can't purchase them
  30.  * anywhere anymore...)
  31.  *
  32.  * Email correspondence to linhart@remus.rutgers.edu.
  33.  *
  34.  * Disclaimer:  This program works for me, at the moment.  I've never seen
  35.  *              any Infocom source code(*).  Nobody within the company told
  36.  *              me any technical details.   I'm just an independent public
  37.  *              domain software author.  If I-Need-Magic sues, I'll
  38.  *              cheerfully turn over all zero profits I made on this program.
  39.  *
  40.  * * (Well, maybe one function.  I noticed the Beyond Zork MS-DOS interpreter
  41.  *    was in MSC, so I mailed them a MSC function to get the screen size from
  42.  *    the BIOS instead of the stupid SETUP.EXE method, so the interpreter
  43.  *    could figure out when my VGA was in 50 line mode.  Some time later, a
  44.  *    new text game was released, with VisiClues.  I started it in 50-line
  45.  *    mode, but the screen was reset to 25-line CGA color mode.  And then the
  46.  *    text ran off the bottom of the screen and scrolled as if it were still
  47.  *    50 lines long.  I'd mail another helpful letter, but it's too late now.)
  48.  */
  49.  
  50. #define MAXCOL  79
  51. #define BUFSIZ  512
  52.  
  53. #if !defined(__STDC__) && !defined(__GNUC__) && !defined(__TURBOC__)
  54. #error This is an ANSI-complaint.  It looks like you are not ANSI-compliant.
  55. #endif
  56.  
  57. #include <stdio.h>
  58. #include <stdlib.h>
  59. #include <stdarg.h>
  60. #include <string.h>
  61. #include <ctype.h>
  62.  
  63. #ifndef SEEK_SET
  64. #define SEEK_SET        0
  65. #endif
  66.  
  67. #define S_BLANK         1
  68. #define S_MACRO1        2
  69. #define S_MACRO2        3
  70. #define S_MACRO3        4
  71. #define S_CAPS          5
  72. #define S_PUNC          6
  73. #define S_FILLER        6
  74. #define S_OFF           7
  75.  
  76. /* the 5-bit character set */
  77. const char err_chars[7] = {
  78.         /* null thrown in for string handling */
  79.         '\0',
  80.         /* special codes above */
  81.         ' ', '1', '2', '3', '^', '@',
  82.         /* followed by: */
  83. };
  84.  
  85. typedef const char alfabet[26];
  86.  
  87. alfabet
  88. lower = {
  89.         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  90.         'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
  91.         },
  92. upper = {
  93.         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  94.         'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
  95.         },
  96. punct = {
  97.         '\0' /* ASCII literal */, '\n',
  98.         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  99.         '.', ',', '!', '?', '_', '#', '\'', '\"', '/', '\\', '-', ':', '(', ')'
  100.         };
  101.  
  102. char *macros[3][32];
  103.  
  104. typedef unsigned char   byte;
  105. typedef unsigned short  word;
  106. typedef unsigned short  z_word;
  107.  
  108. struct info_header {
  109.         byte    z_version;
  110.         byte    flags;
  111.         z_word  release;
  112.         z_word  resident_size;
  113.         z_word  game_offset;
  114.         z_word  vocab_offset;
  115.         z_word  object_offset;
  116.         z_word  variable_offset;
  117.         z_word  save_area_size;
  118.         z_word  script_status;
  119.         char    rev_date[6];
  120.         z_word  macro_offset;
  121.         z_word  verify_length;
  122.         z_word  verify_checksum;
  123.         z_word  reserved[17];
  124. };
  125.  
  126. FILE    *infile;
  127. short   column = 0,
  128.         columns = 0;
  129. char    show_flags = 0,
  130.         numbers = 0,
  131.         macro_dump = 0,
  132.         did_file = 0;
  133.  
  134. unsigned
  135. unzword ( z_word z )
  136. {
  137.         byte *zp = (byte *)&z;
  138.         return (zp[0] << 8) + zp[1];
  139. }
  140.  
  141. void
  142. newline ( void )
  143. {
  144.         putchar('\n');
  145.         column = 0;
  146. }
  147.  
  148. short
  149. end_of_text ( word chars )
  150. {
  151.         return chars >> 15;
  152. }
  153.  
  154. char *
  155. expand ( word chars )
  156. {
  157.         static char buf[4] = {0, 0, 0, 0};
  158.  
  159.         buf[2] = (chars & 0x1F) + 1;
  160.         chars >>= 5;
  161.         buf[1] = (chars & 0x1F) + 1;
  162.         chars >>= 5;
  163.         buf[0] = (chars & 0x1F) + 1;
  164.  
  165.         return buf;
  166. }
  167.  
  168. char *
  169. decode ( char *s )
  170. {
  171.         int             len = strlen(s);
  172.         static char     new[BUFSIZ];
  173.         unsigned        newlen = 0;
  174.  
  175.         while (s[len-1] == S_FILLER)
  176.                 s[--len] = '\0';
  177.  
  178.         while (*s) {
  179.                 switch (*s) {
  180.                         case S_MACRO1:
  181.                         case S_MACRO2:
  182.                         case S_MACRO3:
  183. #ifdef VOCAB_ALONE
  184.                                 /* shouldn't appear in vocabulary list */
  185.                                 new [ newlen++ ] = err_chars[*s];
  186. #else
  187.                                 {
  188.                                         char *tmp = macros[(*s)-2][(*(s+1))-1];
  189.                                         s++;
  190.                                         if (tmp) {
  191.                                                 strcpy(&new [ newlen ], tmp);
  192.                                                 newlen += strlen(tmp);
  193.                                         }
  194.                                 }
  195. #endif
  196.                                 break;
  197.                         case S_CAPS:
  198.                                 if (*(s+1) >= S_OFF)
  199.                                         new [ newlen++ ] = upper[*++s - S_OFF];
  200.                                 else
  201.                                         new [ newlen++ ] = err_chars[S_CAPS];
  202.                                 break;
  203.                         case S_PUNC:
  204.                                 if (*(s+1) >= S_OFF)
  205.                                         if (*++s == S_OFF) {
  206.                                                 new [ newlen ] = ((*++s - 1) & 0x03) << 5;
  207.                                                 new [ newlen++ ] += *++s - 1;
  208.                                         } else
  209.                                                 new [ newlen++ ] = punct[*s - S_OFF];
  210.                                 else
  211.                                         new [ newlen++ ] = err_chars[S_PUNC];
  212.                                 break;
  213.                         case S_BLANK:
  214.                                 new [ newlen++ ] = ' ';
  215.                                 break;
  216.                         default:
  217.                                 new [ newlen++ ] = lower[*s - S_OFF];
  218.                 }
  219.                 s++;
  220.         }
  221.  
  222.         new [ newlen ] = '\0';
  223.  
  224.         return new;
  225. }
  226.  
  227. void
  228. disp_ch ( char x )
  229. {
  230.         putchar(x);
  231.         column++;
  232. }
  233.  
  234. void
  235. disp_str ( char *fmt, ... )
  236. {
  237.         va_list         argptr;
  238.         static char     buf[16];
  239.         short           len;
  240.  
  241.         va_start(argptr, fmt);
  242.         vsprintf(buf, fmt, argptr);
  243.         va_end(argptr);
  244.  
  245.         len = strlen(buf);
  246.         printf(buf);
  247.         column += len;
  248. }
  249.  
  250. void
  251. disp_bits ( char c )
  252. {
  253.         unsigned b;
  254.  
  255.         disp_ch(' ');
  256.         for (b = 0x80; b; b >>= 1)
  257.                 disp_ch(c & b ? '1' : '0');
  258. }
  259.  
  260. void
  261. error ( char *fmt, ... )
  262. {
  263.         va_list         argptr;
  264.  
  265.         fprintf(stderr, "\nError: ");
  266.  
  267.         va_start(argptr, fmt);
  268.         vfprintf(stderr, fmt, argptr);
  269.         va_end(argptr);
  270.  
  271.         exit(1);
  272. }
  273.  
  274. void
  275. read_error ( void )
  276. {
  277.         error("Can't read file at offset %04X.\n", ftell(infile));
  278. }
  279.  
  280. void
  281. seek_pos ( unsigned long pos )
  282. {
  283.         if (fseek(infile, pos, SEEK_SET) != 0)
  284.                 error("Can't seek offset %04lX.\n", pos);
  285. }
  286.  
  287. void
  288. dump_vocab ( unsigned long pos )
  289. {
  290.         register unsigned       count = 0, index;
  291.         word                    words;
  292.         int                     vocab_entry_size;
  293.         byte                    letters_per_word,
  294.                                 zwords_per_word;
  295.         short                   entry_width,
  296.                                 entries_per_line;
  297.         char                    format[sizeof("%%-%ds")];
  298.         int                     punct;
  299.         char *                  buf;
  300.  
  301. #ifdef DEBUG
  302.         printf("Vocabulary table at offset %04X\n", pos);
  303. #endif
  304.  
  305.         seek_pos(pos);
  306.  
  307.         /* list of punctuation characters */
  308.         if ((punct = getc(infile)) == EOF)
  309.                 read_error();
  310.         if (punct) {
  311.                 printf("Punctuation: ");
  312.                 for (; punct; punct--)
  313.                         putchar(getc(infile));
  314.                 putchar('\n');
  315.         }
  316.  
  317.         /* size of each vocabulary entry */
  318.         if ((vocab_entry_size = getc(infile)) == EOF)
  319.                 read_error();
  320.  
  321.         /* number of entries */
  322.         if (fread(&words, sizeof(words), 1, infile) < 1)
  323.                 read_error();
  324.         words = unzword(words);
  325.         if (!numbers)
  326.                 printf("%u vocabulary entries\n", words);
  327.  
  328.         letters_per_word = (vocab_entry_size - 3) / 2 * 3;
  329.         zwords_per_word = letters_per_word / 3;
  330.  
  331.         entry_width = letters_per_word + 2;
  332.         if (numbers)
  333.                 entry_width += 5;
  334.         if (show_flags)
  335.                 entry_width += 3 * (columns == 1 ? 9 : 3) + 1;
  336.         entries_per_line = columns ? columns : (MAXCOL + 2) / entry_width;
  337.  
  338.         buf = malloc(letters_per_word + 1);
  339.         sprintf(format, "%%-%ds", letters_per_word);
  340.  
  341.         while ( count < words ) {
  342.                 byte    flags[3];
  343.  
  344.                 ++count;
  345.                 if (numbers)
  346.                         disp_str("%04d ", count);
  347.  
  348.                 for (index = 0; index < zwords_per_word; index++) {
  349.                         word    z;
  350.  
  351.                         if (fread(&z, sizeof(z), 1, infile) < 1)
  352.                                 read_error();
  353.                         z = unzword(z);
  354.                         if (index)
  355.                                 strcat(buf, expand(z));
  356.                         else
  357.                                 strcpy(buf, expand(z));
  358.                 }
  359.  
  360.                 disp_str(format, decode(buf));
  361.  
  362.                 if (fread(flags, sizeof(char), 3, infile) < 3)
  363.                         read_error();
  364.  
  365.                 if (show_flags) {
  366.                         register short n;
  367.  
  368.                         disp_ch(' ');
  369.                         for (n = 1; n <= 3; n++)
  370.                                 if (columns == 1)
  371.                                         disp_bits(flags[n]);
  372.                                 else
  373.                                         disp_str(" %02x", flags[n]);
  374.                 }
  375.  
  376.                 if (entries_per_line > 1 && (count % entries_per_line))
  377.                         disp_str("  ");
  378.                 else
  379.                         newline();
  380.         }
  381.  
  382.         free(buf);
  383.  
  384.         if (column)
  385.                 newline();
  386. }
  387.  
  388. #ifndef VOCAB_ALONE
  389. void
  390. read_macros ( unsigned long pos )
  391. {
  392.         register short  table, elem;
  393.         z_word          macro_offsets[3][32];
  394.  
  395.         seek_pos(pos);
  396.  
  397.         fread(macro_offsets, sizeof(z_word), 3 * 32, infile);
  398.  
  399.         for (table = 0; table < 3; table++)
  400.                 for (elem = 0; elem < 32; elem++) {
  401.                         macros[table][elem] = NULL;
  402.                         if (macro_dump)
  403.                                 printf("Macro %d-%02d: ", table, elem);
  404.                         if ((pos = unzword(macro_offsets[table][elem])) != 0) {
  405.                                 char    macro[BUFSIZ];
  406.                                 z_word  z;
  407.                                 char    *text;
  408.  
  409.                                 seek_pos(pos *= sizeof(z_word));
  410.  
  411.                                 macro[0] = '\0';
  412.                                 do {
  413.                                         if (fread(&z, sizeof(z), 1, infile) < 1)
  414.                                                 read_error();
  415.                                         z = unzword(z);
  416.                                         if (macro[0])
  417.                                                 strcat(macro, expand(z));
  418.                                         else
  419.                                                 strcpy(macro, expand(z));
  420.                                 } while (!end_of_text(z));
  421.  
  422.                                 text = decode(macro);
  423.                                 macros[table][elem] = malloc(strlen(text) + 1);
  424.                                 strcpy(macros[table][elem], text);
  425.  
  426.                                 if (macro_dump)
  427.                                         printf("\"%s\"\n", text);
  428.                         }
  429.                 }
  430. }
  431. #endif
  432.  
  433. void
  434. frob_file ( const char *filename )
  435. {
  436.         struct info_header      header;
  437.  
  438.         if((infile = fopen(filename, "rb")) == NULL)
  439.                 error("Can't open file \"%s\".\n", filename);
  440.  
  441.         printf("%s:\n", filename);
  442.  
  443.         if (fread(&header, sizeof(header), 1, infile) < 1)
  444.                 read_error();
  445.         printf("Release %u / Serial number %.6s\n", unzword(header.release), &header.rev_date[0]);
  446.  
  447.         if (macro_dump)
  448.                 read_macros(unzword(header.macro_offset));
  449.         dump_vocab(unzword(header.vocab_offset));
  450.  
  451.         fclose(infile);
  452. }
  453.  
  454. #ifndef LINT
  455. const char sccsid[] = "@(#) " __FILE__ " by Mike Threepoint compiled " __DATE__;
  456. #endif
  457.  
  458. void
  459. info ( void )
  460. {
  461.         puts(INFO);
  462.         exit(0);
  463. }
  464.  
  465. void
  466. parse_opt ( char p )
  467. {
  468.         switch (p) {
  469.                 case 'w':
  470.                         columns = 0;
  471.                         break;
  472.                 case '#':
  473.                 case 'n':
  474.                         numbers = !numbers;
  475.                         break;
  476.                 case 'f':
  477.                 case 'b':
  478.                         show_flags = !show_flags;
  479.                         break;
  480. #ifndef VOCAB_ALONE
  481.                 case 'm':
  482.                         macro_dump = !macro_dump;
  483.                         break;
  484. #endif
  485.                 case 'h':
  486.                 case '?':
  487.                         info();
  488.                         break;
  489.                 default:
  490.                         if (isdigit(p))
  491.                                 columns = (p - '0');
  492.         }
  493. }
  494.  
  495. void
  496. parse ( char *parm )
  497. {
  498.         switch (*parm) {
  499.                 case '/':
  500.                         parse_opt(*++parm);
  501.                         break;
  502.                 case '-':
  503.                         while (*++parm) parse_opt(*parm);
  504.                         break;
  505.                 default:
  506.                         if (did_file) newline();
  507.                         frob_file(parm);
  508.                         did_file = 1;
  509.         }
  510. }
  511.  
  512. int
  513. main ( const unsigned argc, char *argv[] )
  514. {
  515.         if (argc > 1) {
  516.                 register count;
  517.  
  518.                 if (strcmp(argv[1], "?") == 0)
  519.                         info();
  520.  
  521.                 for (count = 1; count < argc; count++)
  522.                         parse(argv[count]);
  523.  
  524.                 if (did_file) return 0;
  525.         }
  526.  
  527.         info();
  528.         return 1;
  529. }
  530.  
  531.